
function Puzzle(){

    var container = $('<div class="puzzle"></div>'), DomPanel, mainImage;

    /**
     * UI接口
     * @param time
     */
    var handleStatus = {
        0: function () { console.log('游戏装载...') },
        1: function () { console.log('游戏准备就绪!') },
        2: function () { console.log('游戏开始！') },
        3: function () { console.log('游戏暂停！') },
        4: function () { console.log('游戏结束！') },
        5: function () { console.log('游戏超时！') }
    };
    var handleCountTime = function (time) { console.log(time) };
    var handleLoading = function () { console.log('Loading...') };
    var handleReady = function () { console.log('Ready') };
    var handleOver = {
        'success': function () { console.log('GameOver: Successful') },
        'failure': function () { console.log('GameOver: Failure') }
    };

    /**
     * 可配置选项
     * @type {{countTimeNumber: number}}
     */
    var configOption = {
        panelSize: [600, 600],    //棋盘尺寸
        panelResolution: [3, 3],    //分辨率
        countTimeNumber: 0    //游戏计时，单位秒，值为0时不计时
    };

    //提前计算
    var panel_w = configOption.panelSize[0],
        panel_h = configOption.panelSize[1];
    var resol_x = configOption.panelResolution[0],
        resol_y = configOption.panelResolution[1];
    var cell_count = resol_x*resol_y,
        cell_w= panel_w/resol_x,
        cell_h= panel_h/resol_y;
    var cell_move_range = [ -cell_w/2, panel_w-cell_w/2, -cell_h/2, panel_h-cell_h/2 ];    //cell.left[0,1] cell.top[2,3] 的边界


    /**
     * 拼盘单元格，固定的容器
     * @param id 固定不变
     * @param cellId 装载的变动的贴片ID
     * @method checkMatching 检测是否区配
     * @method create
     */
    function Grid(i){ this.id= i; this.cellId = null }
    Grid.prototype.checkMatching= function(){ return this.id==this.cellId?true:false };
    Grid.prototype.create = function () {
        var position = [cell_w*(this.id%resol_x), cell_h*parseInt(this.id/resol_x)];
        DomPanel.before( $('<span class="grid3"></span>').css({ left: position[0], top: position[1] }) );
        this.position= position;
    };

    /**
     * 拼图贴片
     * @param id 固定不变
     * @param gridId 置入的变动的单元ID
     * @method addToGrid 装入对应单元格
     * @method moveToGrid 移入对应单元格
     */
    function Cell(i){ this.id = i; this.gridId = null }
    Cell.prototype.create= function(){ this.box=$('<li></li>').css({backgroundImage:'url('+mainImage+')'}).appendTo(DomPanel) };
    Cell.prototype.toGrid = function (grid) { this.gridId = grid.id; grid.cellId = this.id; this.position = grid.position };
    Cell.prototype.addToGrid= function(grid){ this.toGrid(grid); this.box.css( {left: grid.position[0],top: grid.position[1] } ) };
    Cell.prototype.moveToGrid= function(grid){
        this.toGrid(grid);
        this.box.animate({left: grid.position[0], top: grid.position[1]},function(){ if(this.gridId==null) this.gridId = null })
    };
    Cell.prototype.getStyle= function () { return [this.box.css('left'), this.box.css('top')] };

    /**
     * 拼图拼盘
     * @param arrGrid 单元格集
     * @param arrCell 贴片集
     */
    var Panel= new function(){
        var randomArray = [];
        var arrGrid= [], arrCell = [];
        var cellMap= {};    //单元索引[坐标-序号]
        var gridActiveId = null;    //激活的单元格ID

        function addCellToGrid(cell,gridId) { var grid = arrGrid[gridId]; grid.cellId = cell.id; cell.addToGrid(grid) }
        function checkOver(){
            for(var i=0, len=arrGrid.length; i<len; i++){
                if(!arrGrid[i].checkMatching()) return;
                if(i==len-1) gameComplete();
            }
        }
        //基础安装
        this.install = function () {
            //遍历格子总数,创建拼盘格子
            for(var i=0; i<cell_count; i++){
                randomArray.push(i);    //随机原数组
                var grid = new Grid(i); grid.create(); arrGrid.push(grid);    //单元格
                var cell = new Cell(i); cell.create(); arrCell.push(cell);    //贴片
                cellMap[i%resol_x+'-'+parseInt(i/resol_x)]= i;    //建立索引 位置-编号{0-1: 1}
            }
        };
        //初始化
        this.init = function () {
            gridActiveId = null;
            //打乱随机数组
            randomArray.sort( function(a, b) { return Math.random()>.5 ? -1 : 1 } );
            //拼盘渲染
            for(var i=0; i<randomArray.length; i++){ addCellToGrid(arrCell[i], randomArray[i]) }
        };
        //单元格响应
        this.checkGrid = function (index,x, y) {
            var cmr = cell_move_range;
            if(x<=cmr[0] || x>=cmr[1] || y<=cmr[2] || y>=cmr[3]){ gridActiveId = null; return}
            var indexText= parseInt((x+cell_w/2)/cell_w)+'-'+parseInt((y+cell_h/2)/cell_w);
            gridActiveId = cellMap[indexText];    //映射目标单元格（地图）
            container.attr('active-tar', gridActiveId);
        };
        //拖动结束
        this.dragEnd = function (index) {
            container.attr('active-tar', 100);
            //当前
            var curCell= arrCell[ index ];
            var curCellGridId= curCell.gridId==null?null:curCell.gridId;
            var curGrid = curCellGridId==null?null:arrGrid[curCellGridId];

            //是否有目标
            if(gridActiveId == null){
                //这里有个BUG:操作[点击不移动]时，不产生[gridActiveId]变化
                //解决办法：改touchend事件为swipeend
                curCell.addToGrid( {id: null, position: curCell.getStyle() } );    //如果没有目标单元格，则要清除当前贴片的单元格
                if(curCellGridId!=null){ curGrid.cellId= null }
            }else{
                //目标
                var tarGrid = arrGrid[ gridActiveId ];
                var tarGridCellId= tarGrid.cellId==null?null:tarGrid.cellId;
                var tarCell= tarGridCellId==null?null:arrCell[ tarGridCellId ];

                //目标单元是否为空
                if(tarCell==null){
                    if(curGrid) curGrid.cellId = null;    //闲置贴片往里放时，贴片无容器，需判断后处理
                }else{
                    if(curGrid){
                        tarCell.moveToGrid( curGrid );    //目标贴片放至当前网格
                    }else{
                        //如目标贴片无交换的单元格则，则放至置换贴片的位置
                        var pos = curCell.position;
                        tarCell.moveToGrid( {id: null, position: pos } );
                    }
                }
                curCell.moveToGrid( tarGrid );    //当前贴片放至目标网格
                checkOver();
                gridActiveId = null;
            }

        }
    };

    /**
     * * 流程 ****************************************************************************************
     * @type {number}********************************************************************************
     */
    var gameStatus = 0;    //当前状态 Set Game Status: 0
    var gameResult = 'failure';
    // 计时器[initGame gameStart gamePause]
    var countTime= new function(){
        var time, T, me=this;
        this.init= function(){clearInterval(T); time= configOption.countTimeNumber};
        this.start= function(){
            if(configOption.countTimeNumber==0) return;
            T= setInterval(function(){
                time--; handleCountTime(time); if(time<=0){ gameTimeout(); setTimeout(function(){ me.init() },500) }
            },1000)
        };
        this.pause = function () { clearInterval(T) }
    };

    //基础设置
    function setBase(imgurl) {
        if(gameStatus!=0) return;
        handleLoading(container);
        container.css({width: panel_w+'px', height: panel_h+'px' });
        DomPanel= $('<ul class="grid3"></ul>').appendTo(container);
        mainImage = imgurl;
        //拼盘装载
        Panel.install();

        //进入初始化
        initGame();

        //主图加载
        var img = new Image; img.onload = function () { gameReady() }; img.src = imgurl;
        //操作监听
        LIM.bind('dragstart', container[0], function(e) {
            if(gameStatus!=2) return;
            //e.preventDefault();
            if(e.target.tagName=='LI'){
                var tar= e.target,
                    index= $(e.target).index(),
                    l= parseInt($(tar).css('left')),
                    t= parseInt($(tar).css('top'));
                container.attr('active-cur', index);
                lim.start(e , {
                    start: function () { },
                    process: function (ox, oy, x, y) { Panel.checkGrid(index, l+ox, t+oy) },
                    end: function (ox, oy, time) { container.attr('active-cur', 100); Panel.dragEnd(index) },
                    auto: [
                        { type: 'MOVE', target: [ { dom:tar, style:{left: l, top: t } } ] }
                    ]
                })

            }
        });
    }

    //游戏初始  //初始化计时器  //打乱基础数据
    function initGame() { countTime.init(); Panel.init() }

    //准备就绪  //Set Game Status: 1
    function gameReady() { gameStatus = 1; handleReady() }

    //游戏开始  //Set Game Status: 2  //计时开始
    function gameStart(Promise) { if(gameStatus!=1 && gameStatus!=3){ Promise.error(gameStatus); return }; Promise.success(gameStatus); gameStatus = 2; countTime.start() }

    //暂停     //Set Game Status: 3  //计时暂停
    function gamePause() { if(gameStatus!=2) return; gameStatus = 3; countTime.pause() }

    //流程结束  //Set Game Status: 4  //计时暂停
    function gameComplete() { gameStatus = 4; countTime.pause(); setTimeout(handleOver['success'],1000) }

    //游戏超时  //Set Game Status: 5
    function gameTimeout() { gameStatus = 5; handleOver[gameResult]() }

    //再来一次
    function gameAgain() { if(gameStatus<4) return; initGame(); gameReady() }


    return {
        install: setBase,
        start: gameStart,
        pause: gamePause,
        again: gameAgain,
        config: function (option) {
            $.extend(configOption, option);
            panel_w = configOption.panelSize[0];
            panel_h = configOption.panelSize[1];
            resol_x = configOption.panelResolution[0];
            resol_y = configOption.panelResolution[1];
            cell_count = resol_x*resol_y;
            cell_w= panel_w/resol_x;
            cell_h= panel_h/resol_y;
            cell_move_range = [ -cell_w/2, panel_w-cell_w/2, -cell_h/2, panel_h-cell_h/2 ];
        },

        setHandleLoading: function (fn) { handleLoading = fn },
        setHandleReady: function(fn){ handleReady = fn },
        setHandleCountTime: function (fn) { handleCountTime = fn },
        setHandleGameSuccess: function (fn) { handleOver['success'] = fn },
        setHandleGameFail: function (fn) { handleOver['failure'] = fn }
    };
}







